package br.edu.ifrn.potigol.lang;

import br.edu.ifrn.potigol.lang.PotigolClass;
import br.edu.ifrn.potigol.lang.PotigolObject;
import br.edu.ifrn.potigol.lang.PotigolRuntime;
import br.edu.ifrn.potigol.lang.ValueObject;

/**
 * Exceção que pode ser capturada em runtime.  
*/
@SuppressWarnings("serial")
public class PotigolException extends Exception {
  private PotigolClass runtimeClass;
  
  /**
   * Cria uma nova exceção de uma classe de tempo de execução.
   * @param runtimeClass Classe de exceção dentro da linguagem.
   * @param message Mensagem da exceção.
   */
  public PotigolException(PotigolClass runtimeClass, String message) {
    super(message);
    this.runtimeClass = runtimeClass;
  }

  /**
   * Cria uma nova exceção de uma classe de tempo de execução.
   * @param runtimeClass Classe de exceção dentro da linguagem.
   */
  public PotigolException(PotigolClass runtimeClass) {
    super();
    this.runtimeClass = runtimeClass;
  }
  
  /**
   * Cria uma nova exceção de uma classe de tempo de execução.
   * @param runtimeClassName Nome da classe de exceção dentro da linguagem.
   * @param message Mensagem da exceção.
   */
  public PotigolException(String runtimeClassName, String message) {
    super(message);
    setRuntimeClass(runtimeClassName);
  }
  
  /**
   * Cria uma nova exceção da classe Exception.
   * @param message Mensagem da exceção.
   */
  public PotigolException(String message) {
    super(message);
    this.runtimeClass = PotigolRuntime.getExceptionClass();
  }
  
  /**
   * Envolve uma exceção para passá-la para o tempo de execução.
   * @param inner Classe de exceção.
   */
  public PotigolException(Exception inner) {
    super(inner);
    setRuntimeClass(inner.getClass().getName());
  }
  
  /**
   * Retorna a instância de tempo de execução da exceção PotigolException.
   */
  public PotigolObject getRuntimeObject() {
    PotigolObject instance = runtimeClass.newInstance(this);
    instance.setInstanceVariable("mensagem", new ValueObject(getMessage()));
    return instance;
  }
  
  /**
   * Retorna a classe de exceção dentro da linguagem.
   */
  public PotigolClass getRuntimeClass() {
    return runtimeClass;
  }

  /**
   * Associa uma nova classe de exceção.
   * @param name Nome da classe de exceção a ser associada.
   */
  protected void setRuntimeClass(String name) {
    runtimeClass = PotigolRuntime.getExceptionClass().subclass(name);
  }
}